package com.own.business.login.core.util;

import com.own.business.login.common.property.LoginProperty;
import com.own.business.login.core.core.LoginSecuritySpringHook;
import com.own.business.login.core.entity.vo.TokenResponseVo;
import com.own.business.login.core.hook.AfterLoginSuccessHook;
import com.own.business.login.core.hook.GetUserAccountTypeHook;
import com.own.business.login.core.hook.GetUserNameHookImpl;
import com.own.business.login.core.service.AutoLoginService;
import com.own.component.client.base.RequestClientManager;
import com.own.component.common.exception.BusinessSimpleException;
import com.own.component.common.login.user.DefaultLoginUser;
import com.own.component.log.login.util.LogLoginUtil;
import com.own.component.token.base.RequestTokenManager;
import com.own.component.token.base.StoreTokenManager;
import com.own.constant.ConstantAccount;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.function.Supplier;

/**
 * LoginCommonUtil
 *
 * @author chenxueli
 * @date 2022-11-13 11:51:00
 */
@Slf4j
@Component
public class LoginCommonUtil {

    @Resource
    private LoginProperty loginProperty;
    @Resource
    private AutoLoginService autoLoginService;

    @Resource
    private GetUserNameHookImpl getUserNameHookImpl;
    @Resource
    private GetUserAccountTypeHook getUserAccountTypeHook;

    @Resource
    private StoreTokenManager storeTokenManager;
    @Resource
    private RequestTokenManager requestTokenManager;
    @Resource
    private RequestClientManager requestClientManager;

    @Resource
    private LoginSecuritySpringHook loginSecuritySpringHook;

    @Resource
    private List<AfterLoginSuccessHook> afterLoginSuccessHookList;

    @Resource
    private LogLoginUtil logLoginUtil;

    /**
     * 根据用户id登录
     *
     * @param userId   用户id
     * @param request  请求信息
     * @param response 响应信息
     * @return token
     */
    public TokenResponseVo loginByUserId(Long userId, HttpServletRequest request, HttpServletResponse response) {
        // 获取登录的客户端id
        var client = requestClientManager.client(request);
        // 获取账号类型 1=普通账号 2=管理员
        var accountType = getUserAccountTypeHook.get(userId);
        // 登录隐私验证（安全验证）
        var entity = loginSecuritySpringHook.check(client, userId, ConstantAccount.TypeEnum.of(accountType), request);
        if (!entity.flag()) {
            throw new BusinessSimpleException(entity.code(), entity.message());
        }
        // 生成token
        var token = storeTokenManager.createToken(userId);
        // 保存token信息
        requestTokenManager.save(token, request, response);
        // 创建并保存刷新token的信息
        var refreshToken = loginProperty.getCreateRefreshTokenInLogin()
                ? autoLoginService.createAutoLoginKey(token, client, userId)
                : null;
        // 获取用户名信息
        var userName = getUserNameHookImpl.getUserName(userId);
        // 保存信息
        var loginUser = new DefaultLoginUser(token, userId, userName, accountType, client);
        // 登录成功之后的日志记录
        logLoginUtil.success(loginUser);
        // 登录成功之后调用的内容信息
        afterLoginSuccessHookList.forEach(hook -> hook.run(loginUser));
        // 返回token信息
        return new TokenResponseVo(userId, token, refreshToken, 7200L);
    }

    /**
     * 通用登录方法
     *
     * @param getUserIdFunction 获取用户id的方法
     * @param request           请求信息
     * @param response          响应信息
     * @return token
     */
    public TokenResponseVo login(Supplier<Long> getUserIdFunction, HttpServletRequest request, HttpServletResponse response) {
        // 用户信息登录
        var userId = getUserIdFunction.get();
        // 根据用户id设置登录信息
        return loginByUserId(userId, request, response);
    }

}
